﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using System.IO;
using System.Xml.Serialization;
using System.Web;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Remoting.Messaging;

namespace System
{
    public static class ObjectConvertExtension
    {
        /// <summary>
        /// tries a to convert a object to a byte
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>byte object of the object.</returns>
        public static byte ToByte(this object anonymousObject)
        {
            if (anonymousObject == null) return 0;

            try
            {
                return Convert.ToByte(anonymousObject);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// tries a to convert a object to a Char
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>Char object of the object.</returns>
        public static char ToChar(this object anonymousObject)
        {
            if (anonymousObject == null) return Char.MinValue;

            try
            {
                return Convert.ToChar(anonymousObject);
            }
            catch
            {
                return Char.MinValue;
            }
        }

        /// <summary>
        /// tries a to convert a object to a Decimal
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>Decimal object of the object.</returns>
        public static Decimal ToDecimal(this object anonymousObject)
        {
            if (anonymousObject == null) return 0;

            try
            {
                return Convert.ToDecimal(anonymousObject);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// tries a to convert a object to a Double
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>Double object of the object.</returns>
        public static Double ToDouble(this object anonymousObject)
        {
            if (anonymousObject == null) return 0;

            try
            {
                return Convert.ToDouble(anonymousObject);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// tries a to convert a object to a Short
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>Short object of the object.</returns>
        public static short ToShort(this object anonymousObject)
        {
            if (anonymousObject == null) return 0;

            try
            {
                return Convert.ToInt16(anonymousObject);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// tries a to convert a object to a Int16
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>Int16 object of the object.</returns>
        public static Int16 ToInt16(this object anonymousObject)
        {
            if (anonymousObject == null) return 0;

            try
            {
                return Convert.ToInt16(anonymousObject);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// tries a to convert a object to a Int32
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>Int32 object of the object.</returns>
        public static Int32 ToInt32(this object anonymousObject)
        {
            if (anonymousObject == null) return 0;

            try
            {
                return Convert.ToInt32(anonymousObject);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// tries a to convert a object to a Int
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>Int object of the object.</returns>
        public static int ToInt(this object anonymousObject)
        {
            if (anonymousObject == null) return 0;

            try
            {
                return Convert.ToInt32(anonymousObject);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// tries a to convert a object to a Int64
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>Int64 object of the object.</returns>
        public static Int64 ToInt64(this object anonymousObject)
        {
            if (anonymousObject == null) return 0;

            try
            {
                return Convert.ToInt64(anonymousObject);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// tries a to convert a object to a long
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>long object of the object.</returns>
        public static long ToLong(this object anonymousObject)
        {
            if (anonymousObject == null) return 0;

            try
            {
                return Convert.ToInt64(anonymousObject);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// tries a to convert a object to a bool
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>bool object of the object.</returns>
        public static bool ToBool(this object anonymousObject)
        {
            if (anonymousObject == null) return false;
            if (anonymousObject.GetType() == typeof(int))
            {
                if (anonymousObject.ToInt() == 1) return true;

                return false;
            }

            try
            {
                return Convert.ToBoolean(anonymousObject);
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// tries a to convert a object to a Boolean
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>Boolean object of the object.</returns>
        public static Boolean ToBoolean(this object anonymousObject)
        {
            if (anonymousObject == null) return false;
            if (anonymousObject.GetType() == typeof(int))
            {
                if (anonymousObject.ToInt() == 1) return true;

                return false;
            }

            try
            {
                return Convert.ToBoolean(anonymousObject);
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Returns String.Empty on null objects or null instances
        /// </summary>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>ToString() or String.Empty if NULL</returns>
        public static string ToStringEx(this object anonymousObject)
        {
            if (anonymousObject == null) return String.Empty;

            try
            {
                return anonymousObject.ToString();
            }
            catch
            {
                return String.Empty;
            }
        }

        /// <summary>
        /// Creates a new instance of the type you want to cast or convert too. Object must match casting type passed.
        /// </summary>
        /// <typeparam name="T">The type of the members of values.</typeparam>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>new instance of type</returns>
        public static T ToNewType<T>(this object anonymousObject)
        {
            try
            {
                T typeobj = Activator.CreateInstance<T>();

                if (anonymousObject == null) return typeobj;
                if (anonymousObject.GetType() != typeobj.GetType()) return typeobj;

                typeobj = (T)anonymousObject;

                return typeobj;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// The type you want to cast or convert too. Object must match casting type passed.
        /// </summary>
        /// <typeparam name="T">The type of the members of values.</typeparam>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>new instance of type</returns>
        public static T ToType<T>(this object anonymousObject)
        {
            try
            {
                return (T)anonymousObject;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Checks an object for null
        /// </summary>
        /// <param name="anonymousObject">Current object. Can be null.</param>
        /// <returns>True if is null and False if is not null.</returns>
        public static bool isNull(this object anonymousObject)
        {
            return (anonymousObject == null);
        }

        /// <summary>
        /// Check an object for null or is instanced.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="anonymousObject"></param>
        /// <returns>True if is null or is not instanced of type passed. False if is not null or is an instance of the passed type.</returns>
        public static bool isOfInstanced<T>(this object anonymousObject)
        {
            try
            {
                if (anonymousObject == null) return false;
                if (anonymousObject.GetType() != typeof(T)) return false;
                
                T typeobj = Activator.CreateInstance<T>();
                
                return anonymousObject.GetType().IsInstanceOfType(typeobj);
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Automatically binds the values of a property to another class. Note: property name case is ignored.
        /// Creates a new instance of the class that is returned.
        /// </summary>
        /// <typeparam name="T">The type of the members of values.</typeparam>
        /// <param name="anonymousObject">Current object. Can not be null.</param>
        /// <returns>the class you want to bind the property values to.</returns>
        public static T BindPropertiesValues<T>(this object anonymousObject)
        {
            try
            {
                if (anonymousObject == null) return (T)anonymousObject;

                Type tSrcObject = anonymousObject.GetType();
                T typeobj = Activator.CreateInstance<T>();
                Type tDesObject = typeobj.GetType();


                PropertyInfo[] pfSrcobjs = tSrcObject.GetProperties();
                PropertyInfo[] pfDescobjs = tDesObject.GetProperties();

                foreach (var pitem in pfDescobjs)
                {
                    var pinfo = pfSrcobjs.Where(
                                                p =>
                                                    p.Name.Equals(pitem.Name, StringComparison.OrdinalIgnoreCase) && // Same Property name
                                                    p.CanWrite && // make sure we can write to the property
                                                    p.MemberType == MemberTypes.Property && // Make sure is a property
                                                    p.PropertyType == pitem.PropertyType // make sure the same data type
                                                ).FirstOrDefault();
                    
                    if (pinfo != null)
                    {
                        try { pitem.SetValue(typeobj, pinfo.GetValue(anonymousObject, null), null); }
                        catch { continue; }
                    }
                }

                return typeobj;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Gets the current assembly guid for the object. If object is null
        /// returns empty guid.
        /// </summary>
        /// <param name="anonymousObject"></param>
        /// <returns></returns>
        public static Guid GetGuid(this object anonymousObject)
        {
            if (anonymousObject == null) return Guid.Empty;
            Type typValue = anonymousObject.GetType();

            if (typValue.isNull() == false) return typValue.GUID;

            return Guid.Empty;
        }
    }
}
